
using PolicyAlgebra.Type;
using PolicyAlgebra.Util;

namespace PolicyAlgebra.Type
{
	///<summary>
	///    This class represents an actual (portion of a) security
	///    policy as is defined by the algebra. This class is the
	///    initiator for all opeartion upon a policy.
	///</summary>
	public class Policy 
	{ 
		// This is used to perform all operations of the algebra and
		// to check permissions assigned over object for particular
		// roles.
		private RoleObjectPermissionSetSetAssociationSetDict ropdict;

		///<summary>
		/// Constructor.
		///</summary>
		public Policy() 
		{
			ropdict = new RoleObjectPermissionSetSetAssociationSetDict();
		}


		///<summary>
		/// Adds a definition of the permissions for a role to the policy.
		///</summary>
		public void AddDefinition(Role role, ObjectPermissionSetSetAssociationSet set)
		{
			if (! ropdict.ContainsKey(role)) 
			{
				ropdict.Add(role, set);
			} 
			else {
				ropdict[role].AddMembers(set);
			}
		}


		///<summary>
		/// Property for the set of roles that have associated permissions
		/// defined by this policy.
		///</summary>
		///<returns>
		/// The set of roles that have defined permissions in this policy.
		///</returns>
		public Set<Role> Roles
		{
			get
			{
				Set<Role> ret = new Set<Role>();

				foreach(Role r in ropdict.Keys)
				{
					ret.AddMember(r);
				}

				return ret;
			}
		}


		//
		// Outer algebra operators.
		
		///<summary>
		/// Perfrom outer conjunction on two policies without changing
		/// the two original policies.
		///</summary>
		///<returns>The outer conjunction of the two supplied policies,
		/// possibly an empty policy.
		///</returns>
		public Policy OuterConjunction(Policy p1, Policy p2)
		{
			Policy newpol = new Policy();
			return newpol;
		}


		///<summary>
		/// Perfrom outer disjunction on two policies without changing
		/// the two original policies.
		///</summary>
		///<returns>The outer disjunction of the two supplied policies,
		/// possibly an empty policy.
		///</returns>
		public Policy OuterDisjunction(Policy p1, Policy p2)
		{
			Policy[] polpair = { p1, p2}; // Used below for a more elegant loop
			Policy newpol = new Policy();

			foreach (Policy p in polpair)
			{
				foreach (Role r in p.ropdict.Keys)
				{
					foreach (ObjectPermissionSetSetAssociationSet opssas in p.ropdict[r])
					{
						newpol.AddDefinition(r, opssas);
					}
				}
			}

			return newpol;
		}


		// Inner algebra operators.


		//
		// Comparison operators follow.

		///<summary>
		/// This operator checks two sets for equality.
		///</summary>
		///<param name="p1">The first set in the comparison</param>
		///<param name="p2">The second set in the comparison</param>
		public static bool operator ==(Policy p1, Policy p2)
		{
			return p1.Equals(p2);
		}


		///<summary>
		/// This operator checks two sets for inequality.
		///</summary>
		///<param name="p1">The first set in the comparison</param>
		///<param name="p2">The second set in the comparison</param>
		public static bool operator !=(Policy p1, Policy p2)
		{
			return !(p1 == p2);
		}


		///<summary>
		/// This method checks two sets for equality (the instance that the
		/// method is called upon and the supplied one).
		///</summary>
		///<param name="other">The supplied set for comparison</param>
		public override bool Equals(object other)
		{
			if (!(other is Policy))
			{
				return false;
			}

			Policy p = (Policy) other;

			return this.ropdict == p.ropdict;
		}


		///<summary>
		/// Compute a hashcode for an object of this type.
		///</summary>
		///<returns>Integer hashcode (using the atom's name)</returns>
		public override int GetHashCode()
		{
			return base.GetHashCode();
		}
	}
}
